﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Odelle.WoWArmory
{
    public class Armory
    {
        public enum TypeAccessFrequency
        {
            FrequencyNever,
            FrequencyAlways,
            FrequencyOnceAnHour,
            FrequencyOnceADay,
            FrequencyOnceThreeDays,
            FrequencyOnceAWeek,
            FrequencyOnceTwoWeeks,
            FrequencyOnceAMonth,
            FrequencyOnceThreeMonths,
            FrequencyOnceSixMonths,
            FrequencyOnceAYear,
            FrequencyOnlyOnce
        }

        public TypeAccessFrequency AccessFrequency { set; get; }

        CrawlArmory crawler = null;

        Data.Characters _characters = null;
        public Data.Characters Characters
        {
            get { return _characters; }
        }

        public string Path
        {
            set
            {
                if (_characters != null)
                    _characters.DefaultPath = value;
            }
            get
            {
                if (_characters != null)
                    return _characters.DefaultPath;
                else
                    return "";
            }
        }

        long _armoryAccessCount = 0;
        public long AutoSaveCount
        {
            set;
            get;
        }

        public Armory()
        {
            this.AccessFrequency = TypeAccessFrequency.FrequencyOnceAWeek;

            string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData);
            try
            {
                path = System.IO.Path.Combine(path, @"Odelle");
                if (!System.IO.Directory.Exists(path))
                    System.IO.Directory.CreateDirectory(path);

                path = System.IO.Path.Combine(path, @"ArmoryData");
                if (!System.IO.Directory.Exists(path))
                    System.IO.Directory.CreateDirectory(path);
            }
            catch (Exception)
            {
            }

            this.AutoSaveCount = 30;

            _characters = new Data.Characters();
            _characters.DefaultPath = path;

            Load("");

            crawler = new CrawlArmory();
        }

        ~Armory()
        {
            Sort();
            Save("");
        }

        public void SetCallbackMessenger(CallbackMessenger delegateMessanger)
        {
            if (crawler != null)
                crawler.SetCallbackMessenger(delegateMessanger);
        }

        public void Sort()
        {
            _characters.Sort();
        }

        public bool Save(string path)
        {
            _armoryAccessCount = 0;
            return _characters.Save(path);
        }

        public bool Load(string path)
        {
            _armoryAccessCount = 0;
            return _characters.Load(path);
        }

        public int CrawlGuild(string region, string realm, string guild)
        {
            int count = 0;

            string[] roster = crawler.GetRosterInGuild(region, realm, guild);
            List<Odelle.WoWArmory.Data.CharacterData> charaList = new List<Data.CharacterData>();

            if (roster != null)
            {
                for (int i = 0; i < roster.Length; ++i)
                {
                    Odelle.WoWArmory.Data.CharacterData chara = GetCharacter(Data.CharacterData.NamesToId(region, realm, roster[i]));
                    if (chara != null)
                    {
                        charaList.Add(chara);
                    }
                }
            }

            if (charaList != null)
            {
                count = charaList.Count;

                for (int i = 0; i < count; ++i)
                {
                    _characters.SetData(charaList[i]);
                }

                Sort();
                Save("");
            }

            return count;
        }

        public int UpdateAllCharacters()
        {
            int count = 0;

            for (int i = 0; i < _characters.CharacterDB.Count; ++i)
            {
                string key = this._characters.CharacterDB.Keys.ElementAt<string>(i);
                Data.CharacterData chara = GetCharacter(key);

                if (chara != null)
                    ++count;
            }

            if (count > 0)
            {
                Sort();
                Save("");
            }

            return count;
        }

        public Data.CharacterData GetCharacter(string region, string realm, string character, TypeAccessFrequency accessFrequency)
        {
            return GetCharacter(Odelle.WoWArmory.Data.CharacterData.NamesToId(region, realm, character), accessFrequency);
        }

        public Data.CharacterData GetCharacter(string region, string realm, string character)
        {
            return GetCharacter(Odelle.WoWArmory.Data.CharacterData.NamesToId(region, realm, character), this.AccessFrequency);
        }

        public Data.CharacterData GetCharacter(string characterId)
        {
            return GetCharacter(characterId, this.AccessFrequency);
        }

        public Data.CharacterData GetCharacter(string characterId, TypeAccessFrequency accessFrequency)
        {
            if (characterId == "")
                return null;

            bool isAccess = false;
            Data.CharacterData charaData = _characters.GetData(characterId);

            if (accessFrequency == TypeAccessFrequency.FrequencyNever)
            {
                isAccess = false;
            }
            else if (accessFrequency == TypeAccessFrequency.FrequencyAlways)
            {
                isAccess = true;
            }
            else
            {
                if (charaData != null)
                {
                    DateTime lastupdated = charaData.LastUpdated;
                    TimeSpan span =  (DateTime.Now - lastupdated);

                    isAccess = false;

                    switch (this.AccessFrequency)
                    {
                        case TypeAccessFrequency.FrequencyOnceAnHour:
                            isAccess = (span.TotalHours >= 1.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceADay:
                            isAccess = (span.TotalDays >= 1.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceThreeDays:
                            isAccess = (span.TotalDays >= 3.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceAWeek:
                            isAccess = (span.TotalDays >= 7.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceTwoWeeks:
                            isAccess = (span.TotalDays >= 14.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceAMonth:
                            isAccess = (span.TotalDays >= 30.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceThreeMonths:
                            isAccess = (span.TotalDays >= 90.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceSixMonths:
                            isAccess = (span.TotalDays >= 180.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnceAYear:
                            isAccess = (span.TotalDays >= 365.0);
                            break;
                        case TypeAccessFrequency.FrequencyOnlyOnce:
                            isAccess = false;
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    isAccess = true;
                }
            }


            if (isAccess)
            {
                Data.CharacterData newData = crawler.GetCharacterData(characterId);

                if (newData != null)
                {
                    _characters.SetData(newData);
                    characterId = newData.ID;

                    ++_armoryAccessCount;
                    if (_armoryAccessCount >= this.AutoSaveCount)
                        Save("");
                }
                else
                {
                    Data.CharacterData data = _characters.GetData(characterId);
                    if (data != null)
                    {
                        data.ErrCode = "No Data";
                        data.LastUpdated = DateTime.Now;
                    }
                }
            }

            return _characters.GetData(characterId);
        }

    }
}
